package com.powernobug.service.impl;

import com.github.pagehelper.PageHelper;
import com.powernobug.bean.model.*;
import com.powernobug.bean.vo.PageVo;
import com.powernobug.bean.vo.data.DetailData;
import com.powernobug.bean.vo.param.OrderListParam;
import com.powernobug.mapper.*;
import com.powernobug.service.AdminOrderService;
import com.powernobug.util.MyBatisUtil;
import org.apache.ibatis.exceptions.PersistenceException;
import org.apache.ibatis.session.SqlSession;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author: 肖云戈
 * @CreateTime: 2024-08-21
 * @Description:
 */
public class AdminOrderServiceImpl implements AdminOrderService {
    private static SqlSession tempSession;

    @Override
    public PageVo getOrdersByPage(OrderListParam params) {
        MarketOrderExample example = new MarketOrderExample();

        if (params.getPage() == null || params.getLimit() == null) {
            throw new PersistenceException();
        }
        if (!(params.getSort() == null) && !(params.getOrder() == null)) {
            example.setOrderByClause(params.getSort() + " " + params.getOrder());
        }

        MarketOrderExample.Criteria criteria = example.createCriteria();
        if (params.getUserId() != null && params.getUserId() != 0) {
            criteria.andUserIdEqualTo(params.getUserId());
        }
        if (params.getOrderSn() != null && params.getOrderSn() != 0) {
            criteria.andOrderSnLike("%" + params.getOrderSn() + "%");
        }
        if (params.getStart() != null && params.getEnd() != null) {
            criteria.andAddTimeBetween(params.getStart(), params.getEnd());
        }
        // 请求参数中解析出的OrderStatusArray是String[]格式，无法直接提供给MyBatis进行查询
        // 此处用流手动转换为List<Short> 后再传入即可
        if (params.getOrderStatusArray() != null && params.getOrderStatusArray().length != 0) {
            List<Short> status = Arrays.stream(params.getOrderStatusArray())
                    .map(Short::parseShort)
                    .collect(Collectors.toList());
            criteria.andOrderStatusIn(status);
        }
        criteria.andDeletedEqualTo(false);

        tempSession = MyBatisUtil.getSqlSession();
        MarketOrderMapper marketOrderMapper = tempSession.getMapper(MarketOrderMapper.class);
        PageHelper.startPage(params.getPage(), params.getLimit());
        List<MarketOrder> marketOrders = marketOrderMapper.selectByExample(example);
        MyBatisUtil.releaseSqlSession(tempSession);

        return PageVo.pag(marketOrders);
    }

    /**
     * 连接查询实现，将查询到的多条数据，用流处理整合为1条数据
     * 同时使用了 TypeHandler对 VarChar -> String[] 进行了转换
     */
    @Override
    public DetailData getOrderDetailsById(String id) {
        tempSession = MyBatisUtil.getSqlSession();
        JoinSelectMapper joinSelectMapper = tempSession.getMapper(JoinSelectMapper.class);
        List<DetailData> detailData = joinSelectMapper.selectOrderDetailById(id);
        List<MarketOrderGoods> collectOrderGoods = detailData.stream()
                .map(x -> x.getOrderGoods().get(0))
                .collect(Collectors.toList());
        return DetailData.builder()
                .orderGoods(collectOrderGoods)
                .user(detailData.get(0).getUser())
                .order(detailData.get(0).getOrder())
                .build();
    }

    /**
     * 订单退款
     */
    @Override
    public boolean refund(Map<String, Integer> map) {
        // 一个校验 -> 传入的 orderId、refundMoney 在数据库中一一对应（不能乱改）
        // 三个操作 -> 修改订单状态、商品货品增加、返还优惠券
        MarketOrderExample example = new MarketOrderExample();
        MarketOrderExample.Criteria criteria = example.createCriteria();
        criteria.andIdEqualTo(map.get("orderId"));
        criteria.andOrderStatusEqualTo((short) 202);
        criteria.andActualPriceEqualTo(BigDecimal.valueOf(map.get("refundMoney")));
        criteria.andDeletedEqualTo(false);

        // 创建Order表连接，开始校验逻辑
        tempSession = MyBatisUtil.getSqlSession();
        MarketOrderMapper marketOrderMapper = tempSession.getMapper(MarketOrderMapper.class);
        // 三条件查询，确保查询所得的数据和前端指定要退款的数据一致（校验失败直接提交事务并返回 false）
        List<MarketOrder> marketOrders = marketOrderMapper.selectByExample(example);
        if (marketOrders.isEmpty()) {
            MyBatisUtil.releaseSqlSession(tempSession);
            return false;
        }

        // 确认无误后，开始回退优惠券逻辑，先打开 market_coupon_user 表的连接，根据 order.id -> coupon_user.order_id 查询被目标订单使用过的优惠券
        // 如果查询结果为空，说明目标订单没有使用优惠券，直接进行下一步逻辑
        MarketOrder targetRefundOrder = marketOrders.get(0);
        MarketCouponUserMapper marketCouponUserMapper = tempSession.getMapper(MarketCouponUserMapper.class);
        List<MarketCouponUser> targetRefundCouponUser = marketCouponUserMapper.selectByOrderId(targetRefundOrder.getId());
        if (!targetRefundCouponUser.isEmpty()) {
            // 如果查询有结果，则开始进行优惠券回退逻辑
            // 回退优惠券：需要修改的字段有 market_coupon.total（为0则不做更改，不为零则+1）
            // market_coupon_user.status（1->0）、market_coupon_user.used_time（xxx->null）
            // market_coupon_user.order_id（xxx->null）、market_coupon_user.update_time（xxx->null）
            MarketCouponMapper marketCouponMapper = tempSession.getMapper(MarketCouponMapper.class);
            for (MarketCouponUser oneMarketCouponUser : targetRefundCouponUser) {
                MarketCoupon targetRefundCoupon = marketCouponMapper.selectByPrimaryKey(oneMarketCouponUser.getCouponId());
                targetRefundCoupon.setTotal((targetRefundCoupon.getTotal() == 0) ? 0 : targetRefundCoupon.getTotal() + 1);
                targetRefundCoupon.setUpdateTime(new Date());
                oneMarketCouponUser.setStatus((short) 0);
                oneMarketCouponUser.setUsedTime(null);
                oneMarketCouponUser.setOrderId(null);
                oneMarketCouponUser.setUpdateTime(null);
                // 更新完成后，写回数据库，等待事务提交
                marketCouponUserMapper.updateByPrimaryKey(oneMarketCouponUser);
                marketCouponMapper.updateByPrimaryKey(targetRefundCoupon);
            }
        }

        // 继续打开 market_order_goods 表、market_goods_product 表的连接
        // 按照 market_order.id -> market_order_goods.order_id 查询到该订单包含的所有商品
        MarketOrderGoodsMapper marketOrderGoodsMapper = tempSession.getMapper(MarketOrderGoodsMapper.class);
        List<MarketOrderGoods> marketOrderGoods = marketOrderGoodsMapper.selectByOrderId(targetRefundOrder.getId());
        if (!marketOrderGoods.isEmpty()) {
            // 如果查询有结果，则开始进行商品货物增加逻辑
            // 遍历 market_order_goods.product_id -> market_goods_product.id
            // 更新 market_goods_product.number（xxxx->xxxx+market_order_goods.number）
            MarketGoodsProductMapper marketGoodsProductMapper = tempSession.getMapper(MarketGoodsProductMapper.class);
            for (MarketOrderGoods oneMarketOrderGood : marketOrderGoods) {
                MarketGoodsProduct targetGoodProduct = marketGoodsProductMapper.selectByPrimaryKey(oneMarketOrderGood.getProductId());
                targetGoodProduct.setNumber(targetGoodProduct.getNumber() + oneMarketOrderGood.getNumber());
                targetGoodProduct.setUpdateTime(new Date());
                // 更新完成后，写回数据库，等待事务提交
                marketGoodsProductMapper.updateByPrimaryKey(targetGoodProduct);
            }
        }

        // 最后进行修改订单状态逻辑，防止回退优惠券逻辑和商品货物增加逻辑出现问题
        // 需要修改的字段有 order_status（? -> 203）、refund_amount（null -> actual_price）
        // refund_time（null -> nowDate）、end_time（null -> refund_time）、update_time（null -> refund_time
        // 将查询到的订单数据，按 “修改订单状态” 进行修改
        Date now = new Date();
        targetRefundOrder.setOrderStatus((short) 203);
        targetRefundOrder.setRefundAmount(targetRefundOrder.getActualPrice());
        targetRefundOrder.setRefundTime(now);
        targetRefundOrder.setEndTime(now);
        targetRefundOrder.setUpdateTime(now);
        // 更新完成后，写回数据库，等待事务提交
        marketOrderMapper.updateByPrimaryKey(targetRefundOrder);

        // 提交事务
        MyBatisUtil.releaseSqlSession(tempSession);
        return true;
    }

    /**
     * 订单发货
     */
    @Override
    public boolean ship(Map<String, Object> map) {
        // 一个校验 -> 传入的 orderId 对应的 status 为201(已付款代发货)
        // 三个操作 -> 修改订单状态、修改订单发货编号、修改订单发货公司
        tempSession = MyBatisUtil.getSqlSession();
        MarketOrderMapper marketOrderMapper = tempSession.getMapper(MarketOrderMapper.class);
        MarketOrder marketOrder = marketOrderMapper.selectByPrimaryKey((Integer) map.get("orderId"));
        if (marketOrder == null || marketOrder.getOrderStatus() != 201) {
            MyBatisUtil.releaseSqlSession(tempSession);
            return false;
        }

        marketOrder.setOrderStatus((short) 301);
        marketOrder.setShipSn((String) map.get("shipSn"));
        marketOrder.setShipChannel((String) map.get("shipChannel"));
        marketOrder.setUpdateTime(new Date());
        // 更新完成后，写回数据库，等待事务提交
        marketOrderMapper.updateByPrimaryKey(marketOrder);
        // 提交事务
        MyBatisUtil.releaseSqlSession(tempSession);
        return true;
    }

    /**
     * 订单删除
     */
    @Override
    public boolean delete(Map<String, Integer> map) {
        // 校验：判断订单是否为 用户收货、系统收货、已退款、用户取消、系统取消，否则返回 false 不可删除
        List<Short> deletable = Arrays.asList((short) 102, (short) 103, (short) 203, (short) 401, (short) 402);
        tempSession = MyBatisUtil.getSqlSession();
        MarketOrderMapper marketOrderMapper = tempSession.getMapper(MarketOrderMapper.class);
        MarketOrder marketOrder = marketOrderMapper.selectByPrimaryKey(map.get("orderId"));
        if (marketOrder == null || !deletable.contains(marketOrder.getOrderStatus())) {
            MyBatisUtil.releaseSqlSession(tempSession);
            return false;
        }

        // 修改订单逻辑删除、修改订单中商品的逻辑删除
        MarketOrderGoodsMapper marketOrderGoodsMapper = tempSession.getMapper(MarketOrderGoodsMapper.class);
        List<MarketOrderGoods> marketOrderGoods = marketOrderGoodsMapper.selectByOrderId(marketOrder.getId());
        for (MarketOrderGoods oneMarketOrderGood : marketOrderGoods) {
            oneMarketOrderGood.setDeleted(true);
            oneMarketOrderGood.setUpdateTime(new Date());
            // 更新完成后，写回数据库，等待事务提交
            marketOrderGoodsMapper.updateByPrimaryKey(oneMarketOrderGood);
        }
        marketOrder.setDeleted(true);
        marketOrder.setUpdateTime(new Date());
        // 更新完成后，写回数据库，等待事务提交
        marketOrderMapper.updateByPrimaryKey(marketOrder);

        MyBatisUtil.releaseSqlSession(tempSession);
        return true;
    }
}
